package com.zhifa.graph;


import lombok.Data;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @version V1.0
 * @Copyright - Powered By 基础软件开发部
 * @author: liangzhifa
 * @date: 2022/4/24 8:50
 * @Description: 有向图的实现==》使用《邻接矩阵》的实现方式
 */
@Data
public class GraphWithAdjacencyMatrix<V> implements OrientedGraph<V> {


    /**
     * 节点列表
     */
    private List<V> nodeList;
    /**
     * 存储图形的邻接矩阵
     */
    private Edge<V>[][] adjacencyMatrix;

    public GraphWithAdjacencyMatrix(int size) {
        this.adjacencyMatrix = new Edge[size][size];//初始化邻接矩阵的大小
        this.nodeList = new LinkedList<V>();
    }

    /**
     * 添加节点
     *
     * @param node 节点
     */
    @Override
    public void addNode(V node) {
        int index = nodeList.indexOf(node);
        if (index >= 0) {//已经存在节点，不能重复添加
            throw new RuntimeException("已经存在节点，不能重复添加");
        }
        nodeList.add(node);
    }

    /**
     * 添加边
     */
    @Override
    public void addEdge(Edge<V> edge) {
        int fromNodeIndex = nodeList.indexOf(edge.getFromNode());
        int toNodeIndex = nodeList.indexOf(edge.getToNode());
        this.adjacencyMatrix[fromNodeIndex][toNodeIndex] = edge;//两个点之间挂上关系
    }

    @Override
    public void show() {
        System.out.println("==========有向图遍历===========");
        System.out.println("节点：" + nodeList + ",size:" + nodeList.size());
        for (int i = 0; i < nodeList.size(); i++) {
            for (int j = 0; j < nodeList.size(); j++) {
                System.out.print(adjacencyMatrix[i][j] + "\t");
            }
            System.out.println();
        }


    }

    @Override
    public void BFSGraph() {
        /*已访问过的顶点列表*/
        List<V> visitedList = new LinkedList<>();
        /*待访问的顶点队列*/
        Queue<V> toBeVisitedQueue = new LinkedList<>();
        V rootNode = nodeList.get(0);// TODO: 2022/4/24 以后改为获取组件的起点  这里先写 0
        visitedList.add(rootNode);
        toBeVisitedQueue.offer(rootNode);
        System.out.println("广度优先遍历开始。。。");
        while (!toBeVisitedQueue.isEmpty()) {//队列不为空就证明还有节点需要执行
            /*出队的《同时》把当前节点的《邻接点》也加入队列*/
            V currentNode = toBeVisitedQueue.poll();
            int currentNodeIndex = nodeList.indexOf(currentNode);//拿当前的节点确定邻接矩阵的横坐标
            // TODO: 2022/4/24  这里做《当前节点》业务操作逻辑
            System.out.println("执行节点：" + currentNode);
            for (int j = 0; j < nodeList.size(); j++) {
                Edge<V> adjacencyMatrixEdge = this.adjacencyMatrix[currentNodeIndex][j];
                /*存在《边》 并且这个节点不能被访问过的*/
                if (Objects.nonNull(adjacencyMatrixEdge) && !visitedList.contains(adjacencyMatrixEdge.getToNode())) {
                    V toNode = adjacencyMatrixEdge.getToNode();
                    visitedList.add(toNode);
                    toBeVisitedQueue.offer(toNode);
                }
            }


        }
        System.out.println("广度优先遍历结束。。。");
        //BFSGraph(rootNode, visitedList);
    }

    /**
     * 广度优先遍历
     */
    @Override
    public void BFSGraph(V node, List<V> visitedList) {
        /*只有《待访问》队列有值 并且 《已经访问》过的节点不能包含在里面==》就是没被访问过的*/
        visitedList.add(node);//从跟节点开始遍历
        // TODO: 2022/4/24  这里做根节点业务操作逻辑
        //接下来找到 根节点 的连接点
        int rootIndex = nodeList.indexOf(node);
        List<CompletableFuture<Object>> completableFutureList = new ArrayList<>();
        for (int j = 0; j < nodeList.size(); j++) {
            Edge<V> edge = this.adjacencyMatrix[rootIndex][j];
            if (edge == null) continue;
            // TODO: 2022/4/24 从边里面获取  toNode 的信息
            V toNode = edge.getToNode();
            System.out.println("当前节点：" + edge.getFromNode() + "访问节点：" + toNode);
            /*并发执行每个子节点的指令*/
            CompletableFuture<Object> completableFuture = CompletableFuture.supplyAsync(() -> {
                // TODO: 2022/4/24  操作每个节点 指令

                return "";
            });
            visitedList.add(toNode);
            completableFutureList.add(completableFuture);
        }
        List<Object> resultCollects = new ArrayList<>();
        if (completableFutureList.size() > 0) {
            // 使用allOf方法 节点任务 都执行结束之前一直阻塞
            CompletableFuture<Object>[] completableFutures = completableFutureList.toArray(new CompletableFuture[0]);
            CompletableFuture.allOf(completableFutures).join();
            /*这里是返回的结果*/
            resultCollects = Stream.of(completableFutures).map(CompletableFuture::join).collect(Collectors.toList());
        }


    }


}
